[Talend]ファイル内のEOFを取り除く
不要な制御文字コードを取り除く
データ分析系の案件をやっているといろんな種類のCSVもしくはTSVファイルと連携することがあります。 よくあるケースとして
- 文字コードがSHIFT−JISで連携されてくるケース
- 文字コードがEUCで連携されてくるケース
- 改行コードがCRLFで連携されてくるケース
- 改行コードがCRで連携されてくるケース
- 改行コードがLFで連携されてくるケース
- 項目がスペース埋められて連携されてくるケース
等々
Amazon Redshiftへデータロードする際は文字コードをUTF-8にすることが必須条件となるので、文字コードの変換はよく行います。
ただし、上記のパターンについてはコンポーネント側のオプション等で吸収できるので、連携フォーマットの仕様さえ分かれば問題ないですが、中には制御文字コード等が入ってくるケースもあります。 今回はその制御文字コードのEOF(ファイル終端コード)を取り除くジョブを作ってみました。 利用頻度は少ないかもしれませんが、作ったので備忘録として。
使用したサンプルCSVは ・文字コードはUTF−8 ・改行コードはLF
Sublime Textで開いた場合にEOFがSUBと表示されています。
odコマンドで一応コードとキャラクタ表示をさせたものが以下で、一番最後に1aのコードが入っています。これがEOFのコードとなります。
$ od -cx eof_sample.csv 0000000 " s a m p l e 1 " , 0 , " 0 1 " 7322 6d61 6c70 3165 2c22 2c30 3022 2231 0000020 , " A A " , " 1 " , " 2 0 1 5 1 222c 4141 2c22 3122 2c22 3222 3130 3135 0000040 1 2 0 " , " 9 8 7 6 5 4 " , " 3 3231 2230 222c 3839 3637 3435 2c22 3322 0000060 2 " , " 1 0 " , " 1 2 " , " 3 4 2232 222c 3031 2c22 3122 2232 222c 3433 0000100 5 6 7 8 " , " 0 0 1 " , " サ ** ** 3635 3837 2c22 3022 3130 2c22 e322 b582 0000120 ン ** ** プ ** ** ル ** ** 1 ** ** 83e3 e3b3 9783 83e3 efab 91bc 2020 2020 0000140 " , " 2 0 1 5 1 2 0 9 " \n " s 2220 222c 3032 3531 3231 3930 0a22 7322 0000160 a m p l e 2 " , 0 , " 0 1 " , " 6d61 6c70 3265 2c22 2c30 3022 2231 222c 0000200 B B " , " 1 " , " 2 0 1 5 1 2 0 4242 2c22 3122 2c22 3222 3130 3135 3032 0000220 2 " , " 4 5 6 7 8 9 " , " 4 4 " 2232 222c 3534 3736 3938 2c22 3422 2234 0000240 , " 1 0 " , " 1 1 " , " 3 4 5 6 222c 3031 2c22 3122 2231 222c 3433 3635 0000260 7 8 " , " 0 0 1 " , " サ ** ** ン ** 3837 2c22 3022 3130 2c22 e322 b582 83e3 0000300 ** プ ** ** ル ** ** 2 ** ** " e3b3 9783 83e3 efab 92bc 2020 2020 2220 0000320 , " 2 0 1 5 1 2 0 9 " \n 032 222c 3032 3531 3231 3930 0a22 001a 0000335 $
作成ジョブの概要
今回はファイルの読み込みにtFileInputDelimitedコンポーネントは使わずtFileInputFullRowコンポーネントを使います。このコンポーネントはテキストの1行を1データとして入力し後続のコンポーネントへ渡すためのものです。後続のコンポーネントには文字コード置換させるためのtReplaceコンポーネントを使います。 通常の文字コード置換であればtReplaceコンポーネントの後続にtExtractDelimitedFieldsコンポーネントでデータを1行表現からCSV区切り表現へ変換するもので受けて最終的にtFileOutputDelimitedでファイル出力すればいいのですが、その状態でジョブを実行するとEOFが含まれている行が空行として無駄に出力されてしまいます。 これで特に問題があるわけではないのですが、綺麗にしたいのでtReplaceコンポーネントとtExtractDelimitedFieldsコンポーネントの間にもう一つtFilterRowコンポーネントを挟んで文字置換後に空行の場合は出力しないというものを追加した形でジョブを作成してちょっとスマートにしたいと思います。
実際にジョブを作成してみる
完成形は以下のような感じになります。 tFileInputFullRow の基本設定でEOFの含まれたCSVを指定します。 次に tReplace の基本設定で詳細モードにチェックし、正規表現パターンを登録します。ソースは tFileInputFullRow の line を指定し、パターンとして new String(Character.toChars(0x1a))を指定します。(置換後の部分は""に) 次に tFilterRow の基本設定で条件を指定します。 tFilterRowコンポーネントは、指定したカラムの条件に一致する行だけを抽出するものです。使い方はフィルタリング条件のカラム名を「入力カラム」に、比較条件を「オペレータ」に、比較値を「値」に入力します。 あとはtFilterRowで条件がマッチした行を後続の tExtractDelimitedFields に渡して最終的に tFileOutputDelimited でCSVを書き出してあげれば完成です。
ジョブを実行する
正常にジョブが終了しました。 Sublime Textでみた状態SUBが取り除かれていることが確認できます。 一応odコマンドでコードとキャラクタ表示をさせたものでも確認。最後の1aが正しく取り除かれていることが確認できます。
$ od -cx eof_sample_trance.csv 0000000 " s a m p l e 1 " , 0 , " 0 1 " 7322 6d61 6c70 3165 2c22 2c30 3022 2231 0000020 , " A A " , " 1 " , " 2 0 1 5 1 222c 4141 2c22 3122 2c22 3222 3130 3135 0000040 1 2 0 " , " 9 8 7 6 5 4 " , " 3 3231 2230 222c 3839 3637 3435 2c22 3322 0000060 2 " , " 1 0 " , " 1 2 " , " 3 4 2232 222c 3031 2c22 3122 2232 222c 3433 0000100 5 6 7 8 " , " 0 0 1 " , " サ ** ** 3635 3837 2c22 3022 3130 2c22 e322 b582 0000120 ン ** ** プ ** ** ル ** ** 1 ** ** 83e3 e3b3 9783 83e3 efab 91bc 2020 2020 0000140 " , " 2 0 1 5 1 2 0 9 " \n " s 2220 222c 3032 3531 3231 3930 0a22 7322 0000160 a m p l e 2 " , 0 , " 0 1 " , " 6d61 6c70 3265 2c22 2c30 3022 2231 222c 0000200 B B " , " 1 " , " 2 0 1 5 1 2 0 4242 2c22 3122 2c22 3222 3130 3135 3032 0000220 2 " , " 4 5 6 7 8 9 " , " 4 4 " 2232 222c 3534 3736 3938 2c22 3422 2234 0000240 , " 1 0 " , " 1 1 " , " 3 4 5 6 222c 3031 2c22 3122 2231 222c 3433 3635 0000260 7 8 " , " 0 0 1 " , " サ ** ** ン ** 3837 2c22 3022 3130 2c22 e322 b582 83e3 0000300 ** プ ** ** ル ** ** 2 ** ** " e3b3 9783 83e3 efab 92bc 2020 2020 2220 0000320 , " 2 0 1 5 1 2 0 9 " \n 222c 3032 3531 3231 3930 0a22 0000334 $
まとめ
EOFを取り除くということ自体はあまり需要があるかどうかはわかりませんが、EOF以外にもさまざまな制御コードを取り除く必要があるケースも出てくるかと思いますので、その際はtFilterRowの条件部分を変更すれば利用用途はあるのかなと思います。